package com.xhj.mybatis.reflection.wrapper;

import com.xhj.mybatis.reflection.MetaObject;
import com.xhj.mybatis.reflection.factory.ObjectFactory;
import com.xhj.mybatis.reflection.property.PropertyTokenizer;

import java.util.List;

/**
 * ObjectWrapper
 *
 * @author XJks
 * @description ObjectWrapper 接口用于封装对象的属性访问和操作，支持对普通对象和集合的统一处理。
 * <p>
 * TODO:
 *  包装器：按对象类型分派读写策略。
 *  抽象对“目标对象”的统一访问：
 *      1.get(PropertyTokenizer prop) / set(PropertyTokenizer prop, Object value)
 *      2.findProperty/hasGetter/hasSetter
 *      3.getGetterNames/getSetterNames 等。
 */
public interface ObjectWrapper {

    /**
     * 获取指定属性的值。
     *
     * @param prop 属性分词器，支持多级属性（如 user.address.street）
     * @return 属性的值
     */
    Object get(PropertyTokenizer prop);

    /**
     * 设置指定属性的值。
     *
     * @param prop  属性分词器
     * @param value 要设置的值
     */
    void set(PropertyTokenizer prop, Object value);

    /**
     * 查找属性名，支持驼峰命名到下划线命名的映射。
     *
     * @param name                属性名
     * @param useCamelCaseMapping 是否使用驼峰命名映射
     * @return 实际属性名
     */
    String findProperty(String name, boolean useCamelCaseMapping);

    /**
     * 获取所有可读（getter）属性的名称。
     *
     * @return getter 方法对应的属性名数组
     */
    String[] getGetterNames();

    /**
     * 获取所有可写（setter）属性的名称。
     *
     * @return setter 方法对应的属性名数组
     */
    String[] getSetterNames();

    /**
     * 获取指定属性的 setter 方法参数类型。
     *
     * @param name 属性名
     * @return setter 参数类型
     */
    Class<?> getSetterType(String name);

    /**
     * 获取指定属性的 getter 方法返回类型。
     *
     * @param name 属性名
     * @return getter 返回类型
     */
    Class<?> getGetterType(String name);

    /**
     * 判断是否有指定属性的 setter 方法。
     *
     * @param name 属性名
     * @return 是否有 setter
     */
    boolean hasSetter(String name);

    /**
     * 判断是否有指定属性的 getter 方法。
     *
     * @param name 属性名
     * @return 是否有 getter
     */
    boolean hasGetter(String name);

    /**
     * 实例化属性值（如集合或对象），并返回其 MetaObject 封装。
     *
     * @param name          属性名
     * @param prop          属性分词器
     * @param objectFactory 对象工厂，用于创建新实例
     * @return 封装后的 MetaObject
     */
    MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

    /**
     * 判断当前对象是否为集合类型（如 List、Set）。
     *
     * @return 是否为集合
     */
    boolean isCollection();

    /**
     * 向集合中添加一个元素。
     * 仅当 isCollection() 返回 true 时有效。
     *
     * @param element 要添加的元素
     */
    void add(Object element);

    /**
     * 向集合中批量添加元素。
     * 仅当 isCollection() 返回 true 时有效。
     *
     * @param element 要添加的元素列表
     * @param <E>     元素类型
     */
    <E> void addAll(List<E> element);

}
